export default class utils {
  /**
   * 返回一个格式化日期
   * @param date Date类型
   * @param formatter date || datetime || yyyy年MM月dd日 HH:mm:ss(指定日期格式) || 自定义函数
   * @param isPad 是否补零
   */
  static formatDate(date, formatter, isPad = false) {
    if (!(date instanceof Date)) {
      throw new TypeError("argument date must be a Date");
    }

    //参数归一化
    const formatHelper = function (formatter) {
      if (typeof formatter === "function") {
        return formatter;
      }
      if (typeof formatter !== "string") {
        throw new TypeError("formatter must be a string");
      }
      if (formatter === "date") {
        formatter = "yyyy-MM-dd";
      }
      if (formatter === "datetime") {
        formatter = "yyyy-MM-dd HH:mm:ss";
      }
      const formatFunc = (dateInfo) => {
        const { yyyy, MM, dd, HH, mm, ss, ms } = dateInfo;
        return formatter
          .replaceAll("yyyy", yyyy)
          .replaceAll("MM", MM)
          .replaceAll("dd", dd)
          .replaceAll("HH", HH)
          .replaceAll("mm", mm)
          .replaceAll("ss", ss)
          .replaceAll("ms", ms);
      };
      return formatFunc;
    };
    formatter = formatHelper(formatter);
    const dateInfo = {
      yyyy: date.getFullYear().toString(),
      MM: (date.getMonth() + 1).toString(),
      dd: date.getDate().toString(),
      HH: date.getHours().toString(),
      mm: date.getMinutes().toString(),
      ss: date.getSeconds().toString(),
      ms: date.getMilliseconds().toString(),
    };

    // 补零
    function _pad(prop, len) {
      dateInfo[prop] = dateInfo[prop].padStart(len, "0");
    }

    if (isPad) {
      _pad("yyyy", 4);
      _pad("MM", 2);
      _pad("dd", 2);
      _pad("HH", 2);
      _pad("mm", 2);
      _pad("ss", 2);
      _pad("ms", 3);
    }
    const result = formatter(dateInfo);
    return result;
  }

  // xeutils.toTreeArray优化- 自动添加parentKey
  // 将一个树结构转成数组列表
  static toTreeArray(array, options) {
    const fn = (result, array, parentId, opts) => {
      let optChildren = opts.children;
      let optData = opts.data;
      let optClear = opts.clear;
      let optKey = opts.key;
      let optParentKey = opts.parentKey;
      array.forEach((item) => {
        let children = item[optChildren];
        if (optData) {
          item = item[optData];
        }
        result.push({
          [optParentKey]: parentId,
          ...item,
        });
        if (children && children.length) {
          fn(result, children, item[optKey], opts);
        }
        if (optClear) {
          delete item[optChildren];
        }
      });
      return result;
    };
    return fn([], array, null, {
      parentKey: "parentId",
      key: "id",
      children: "children",
      ...options,
    });
  }
  // 将一个数组列表转成树结构
  static arrayToTree(items, options = {}) {
    if (!Array.isArray(items)) {
      return [];
    }
    const {
      idKey = "id", // id字段名
      parentKey = "parent", // parent字段名
      childrenKey = "children", // children字段名
    } = options;

    const result = [];
    const itemMap = {};

    // 建立映射
    for (const item of items) {
      itemMap[item[idKey]] = { ...item, [childrenKey]: [] };
    }

    // 构建树
    for (const item of items) {
      const id = item[idKey];
      const parentId = item[parentKey];
      const treeItem = itemMap[id];

      if (!parentId || parentId === "" || !itemMap[parentId]) {
        // 没有父节点或父节点不存在，作为根节点
        result.push(treeItem);
      } else {
        // 添加到父节点的children中
        itemMap[parentId][childrenKey].push(treeItem);
      }
    }

    return result;
  }

  static sleepWait(delay = 1000) {
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve(delay);
      }, delay);
    });
  }

  /**
   * 防抖函数
   * @param {Function} fn - 需要防抖的函数
   * @param {number} delay - 延迟时间（毫秒）
   * @returns {Function} - 返回一个防抖后的函数
   */
  static debounce(fn, delay) {
    let timer = null;
    return function (...args) {
      if (timer) {
        clearTimeout(timer); // 如果计时器存在，清除之前的计时器
      }
      timer = setTimeout(() => {
        fn.apply(this, args); // 延迟执行函数
        timer = null; // 执行完后清空计时器
      }, delay);
    };
  }

  // /**
  //  * @param {Function} func
  //  * @param {number} wait
  //  * @param {boolean} immediate
  //  * @return {*}
  //  */
  // static debounce(func, wait, immediate) {
  //   let timeout, args, context, timestamp, result;

  //   const later = function () {
  //     // 据上一次触发时间间隔
  //     const last = +new Date() - timestamp;

  //     // 上次被包装函数被调用时间间隔 last 小于设定时间间隔 wait
  //     if (last < wait && last > 0) {
  //       timeout = setTimeout(later, wait - last);
  //     } else {
  //       timeout = null;
  //       // 如果设定为immediate===true，因为开始边界已经调用过了此处无需调用
  //       if (!immediate) {
  //         result = func.apply(context, args);
  //         if (!timeout) context = args = null;
  //       }
  //     }
  //   };

  //   return function (...args) {
  //     context = this;
  //     timestamp = +new Date();
  //     const callNow = immediate && !timeout;
  //     // 如果延时不存在，重新设定延时
  //     if (!timeout) timeout = setTimeout(later, wait);
  //     if (callNow) {
  //       result = func.apply(context, args);
  //       context = args = null;
  //     }

  //     return result;
  //   };
  // }

  /**
   * This is just a simple version of deep copy
   * Has a lot of edge cases bug
   * If you want to use a perfect deep copy, use lodash's _.cloneDeep
   * @param {Object} source
   * @returns {Object}
   */
  static deepClone(source) {
    if (!source && typeof source !== "object") {
      throw new Error("error arguments", "deepClone");
    }
    const targetObj = source.constructor === Array ? [] : {};
    Object.keys(source).forEach((keys) => {
      if (source[keys] && typeof source[keys] === "object") {
        targetObj[keys] = deepClone(source[keys]);
      } else {
        targetObj[keys] = source[keys];
      }
    });
    return targetObj;
  }

  /**
   * 高亮匹配文本的通用函数
   * @param {string} originText - 原始文本
   * @param {string} matchText - 需要高亮的匹配文本
   * @returns {string} 包含高亮span标签的HTML字符串
   */
  static highlightText(originText, matchText) {
    // 安全校验
    if (!matchText || typeof originText !== "string") return originText;

    // 转义正则特殊字符
    const escapedMatch = matchText.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

    // 创建全局正则表达式（不区分大小写可以加 i 标志）
    const regex = new RegExp(`(${escapedMatch})`, "gi");

    // 替换匹配项
    return originText.replace(regex, '<span class="highlight-text">$1</span>');
  }

  //生成唯一主键id
  static getUUID() {
    return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
      /[xy]/g,
      function (c) {
        const r = (Math.random() * 16) | 0;
        const v = c === "x" ? r : (r & 0x3) | 0x8;
        return v.toString(16);
      }
    );
  }

  /**
   * 通用对象数组排序方法
   * @param {Array} array - 要排序的数组
   * @param {Object} options - 排序选项
   * @param {string} [options.key] - 排序的字段名
   * @param {boolean} [options.desc=false] - 是否降序排序
   * @param {Function} [options.compareFn] - 自定义比较函数，优先级高于key
   * @returns {Array} 排序后的新数组
   */
  static sortBy(array, options = {}) {
    // 创建数组副本以避免修改原数组
    const arr = [...array];

    // 解构配置项
    const { key, desc = false, compareFn } = options;

    // 如果没有提供任何排序条件，返回原数组副本
    if (!key && !compareFn) return arr;

    // 使用自定义比较函数
    if (compareFn && typeof compareFn === "function") {
      return arr.sort((a, b) => (desc ? compareFn(b, a) : compareFn(a, b)));
    }

    // 使用字段名排序
    return arr.sort((a, b) => {
      const valueA = key ? a[key] : a;
      const valueB = key ? b[key] : b;

      // 处理可能为undefined或null的情况
      if (valueA == null && valueB == null) return 0;
      if (valueA == null) return desc ? 1 : -1;
      if (valueB == null) return desc ? -1 : 1;

      // 数值比较
      if (typeof valueA === "number" && typeof valueB === "number") {
        return desc ? valueB - valueA : valueA - valueB;
      }

      // 字符串比较
      if (typeof valueA === "string" && typeof valueB === "string") {
        return desc
          ? valueB.localeCompare(valueA)
          : valueA.localeCompare(valueB);
      }

      // 日期比较
      if (valueA instanceof Date && valueB instanceof Date) {
        return desc
          ? valueB.getTime() - valueA.getTime()
          : valueA.getTime() - valueB.getTime();
      }

      // 默认比较
      return desc
        ? String(valueB).localeCompare(String(valueA))
        : String(valueA).localeCompare(String(valueB));
    });
  }

  //判断当前运行环境是否是移动端
  static isMobile() {
    return /android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(
      navigator.userAgent.toLowerCase()
    );
  }
}
